package com.openx;

import cn.com.sand.ceas.sdk.config.CertCache;
import cn.com.sand.ceas.sdk.config.ConfigLoader;
import cn.com.sand.ceas.sdk.util.AESUtils;
import cn.com.sand.ceas.sdk.util.RSAUtils;
import cn.com.sand.ceas.sdk.util.RandomUtils;
import cn.com.sand.ceas.sdk.util.SignatureUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.FileInputStream;  
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.PublicKey;  
import java.security.cert.Certificate;  
import java.security.cert.CertificateException;  
import java.security.cert.CertificateFactory; 
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Base64;
import java.util.concurrent.ConcurrentHashMap;

public class Sand {
    private static final ConcurrentHashMap<String, PrivateKey> PRIVATE_KEYS = new ConcurrentHashMap<>();
    private static final String PRIVATE_KEY = "PRIVATE_KEY";

    public static PrivateKey getPrivateKey() {
        return PRIVATE_KEYS.get(PRIVATE_KEY);
    }

    public static String getSignContent(Map<String, String> params) {
        StringBuilder content = new StringBuilder();
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            if (key != null && !key.isEmpty() && value != null && !value.isEmpty()) {
                content.append(i == 0 ? "" : "&").append(key).append("=").append(value);
            }
        }
        return content.toString();
    }

    public static String sign(String content, PrivateKey privateKey) {
        try {
            Signature signature = Signature.getInstance("SHA1WithRSA");
            signature.initSign(privateKey);
            signature.update(content.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(signature.sign());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void initPrivateKey(String privateKeyStr) {
        try {
            byte[] keyBytes = Base64.getDecoder().decode(privateKeyStr);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            PRIVATE_KEYS.put(PRIVATE_KEY, privateKey);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void initPrivateKey(String privateKeyPath, String password) {
        String classpathKey = "classpath:";
        InputStream inputStream = null;
        try {
            if (privateKeyPath.startsWith(classpathKey)) {
                inputStream = Sand.class.getClassLoader().getResourceAsStream(privateKeyPath.substring(classpathKey.length()));
            } else {
                inputStream = Files.newInputStream(Paths.get(privateKeyPath));
            }

            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            char[] pwdChar;
            if (password == null || password.trim().equals("")) {
                pwdChar = null;
            } else {
                pwdChar = password.toCharArray();
            }
            keyStore.load(inputStream, pwdChar);

            Enumeration<String> aliases = keyStore.aliases();
            String alias = null;
            if (aliases.hasMoreElements()) {
                alias = aliases.nextElement();
            }
            PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, pwdChar);
            PRIVATE_KEYS.put(PRIVATE_KEY, privateKey);
        } catch (FileNotFoundException e) {
            throw new RuntimeException("私钥不存在");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("算法不存在");
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException ignored) {
                }
            }
        }
    }   

    public static PublicKey loadPublicKey(String cerFilePath) {  
        try (FileInputStream fis = new FileInputStream(cerFilePath)) {  
            CertificateFactory cf = CertificateFactory.getInstance("X.509");  
            Certificate cert = cf.generateCertificate(fis);  
            PublicKey publicKey = cert.getPublicKey();  
            return cert.getPublicKey();
        } catch (CertificateException | IOException e) {  
           throw new RuntimeException(e);
        }
    } 

    public static String encrypt(String plainValue, PublicKey publicKey) {
        try {
            JSONObject param = new JSONObject();

            String aesKey = RandomUtils.genRandomStringByLength(16);
            byte[] aesKeyBytes = aesKey.getBytes(StandardCharsets.UTF_8);

            byte[] encryptValueBytes = AESUtils.encrypt(plainValue.getBytes(StandardCharsets.UTF_8), aesKeyBytes, (String) null);
            param.put("data", Base64.getEncoder().encodeToString(encryptValueBytes));

            byte[] encryptKeyBytes = RSAUtils.encrypt(aesKeyBytes, publicKey);
            param.put("encryptKey", Base64.getEncoder().encodeToString(encryptKeyBytes));

            return param.toJSONString();
        } catch (Exception e) {  
           throw new RuntimeException(e);
        }
    }  
}